libobs_wrapper\display\window_manager/
position_trait.rs

1#[cfg(windows)]
2use windows::Win32::{
3    Foundation::HWND,
4    Graphics::Gdi::{RedrawWindow, RDW_ERASE, RDW_INVALIDATE},
5    UI::WindowsAndMessaging::{
6        SetWindowPos, HWND_BOTTOM, SWP_NOACTIVATE, SWP_NOCOPYBITS, SWP_NOSIZE, SWP_NOZORDER,
7        SWP_SHOWWINDOW,
8    },
9};
10
11use crate::display::window_manager::WindowPositionTrait;
12use crate::display::DISPLAY_POSITIONS;
13use crate::utils::ObsError;
14use crate::{display::ObsDisplayRef, run_with_obs};
15
16impl WindowPositionTrait for ObsDisplayRef {
17    fn set_render_at_bottom(&self, _render_at_bottom: bool) -> Result<(), ObsError> {
18        log::trace!("Set render bottom");
19        #[cfg(windows)]
20        if let Some(m) = self.child_window_handler.as_ref() {
21            let mut m = m
22                .write()
23                .map_err(|e| ObsError::LockError(format!("{:?}", e)))?;
24
25            m.render_at_bottom = _render_at_bottom;
26        }
27        Ok(())
28    }
29
30    fn get_render_at_bottom(&self) -> Result<bool, ObsError> {
31        #[cfg(windows)]
32        if let Some(m) = self.child_window_handler.as_ref() {
33            let m = m
34                .read()
35                .map_err(|e| ObsError::LockError(format!("{:?}", e)))?;
36            return Ok(m.render_at_bottom);
37        }
38
39        Ok(false)
40    }
41
42    fn set_pos(&self, x: i32, y: i32) -> Result<(), ObsError> {
43        log::trace!("Set pos {x} {y}");
44
45        #[cfg(windows)]
46        if let Some(m) = self.child_window_handler.as_ref() {
47            let mut m = m
48                .write()
49                .map_err(|e| ObsError::LockError(format!("{:?}", e)))?;
50
51            assert!(
52                m.obs_display.is_some(),
53                "Invalid state. The display should have been created and set, but it wasn't."
54            );
55
56            let insert_after = if m.render_at_bottom {
57                HWND_BOTTOM
58            } else {
59                HWND::default()
60            };
61
62            m.x = x;
63            m.y = y;
64
65            unsafe {
66                let flags = SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE;
67                // Just use dummy values as size is not changed
68                SetWindowPos(
69                    m.window_handle.get_hwnd(),
70                    Some(insert_after),
71                    x,
72                    y,
73                    1_i32,
74                    1_i32,
75                    flags,
76                )
77                .map_err(|e| ObsError::DisplayCreationError(format!("{:?}", e)))?;
78            }
79
80            // Update color space when window position changes
81            drop(m); // Release the lock before calling run_with_obs
82            self.update_color_space()?;
83            return Ok(());
84        }
85
86        *DISPLAY_POSITIONS
87            .write()
88            .map_err(|e| ObsError::LockError(format!("{:?}", e)))?
89            .get_mut(&self.id)
90            .ok_or_else(|| ObsError::LockError("Position not found".to_string()))? = (x, y);
91
92        self.update_color_space()?;
93        Ok(())
94    }
95
96    fn set_size(&self, width: u32, height: u32) -> Result<(), ObsError> {
97        log::trace!("Set size {width} {height}");
98
99        #[cfg(windows)]
100        if let Some(m) = self.child_window_handler.as_ref() {
101            let mut m = m
102                .write()
103                .map_err(|e| ObsError::LockError(format!("{:?}", e)))?;
104
105            assert!(
106                m.obs_display.is_some(),
107                "Invalid state. The display should have been created and set, but it wasn't."
108            );
109
110            m.width = width;
111            m.height = height;
112
113            unsafe {
114                SetWindowPos(
115                    m.window_handle.get_hwnd(),
116                    None,
117                    m.x,
118                    m.y,
119                    width as i32,
120                    height as i32,
121                    SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW,
122                )
123                .map_err(|e| ObsError::DisplayCreationError(format!("{:?}", e)))?;
124
125                let _ = RedrawWindow(
126                    Some(m.window_handle.get_hwnd()),
127                    None,
128                    None,
129                    RDW_ERASE | RDW_INVALIDATE,
130                );
131            }
132        }
133
134        let pointer = self.display.clone();
135        run_with_obs!(self.runtime, (pointer), move || unsafe {
136            libobs::obs_display_resize(pointer, width, height);
137            // Update color space when window size changes
138            libobs::obs_display_update_color_space(pointer);
139        })
140        .map_err(|e| ObsError::InvocationError(format!("{:?}", e)))?;
141        Ok(())
142    }
143
144    fn get_pos(&self) -> Result<(i32, i32), ObsError> {
145        #[cfg(windows)]
146        if let Some(m) = self.child_window_handler.as_ref() {
147            let m = m
148                .read()
149                .map_err(|e| ObsError::LockError(format!("{:?}", e)))?;
150            return Ok((m.x, m.y));
151        }
152
153        let pos = DISPLAY_POSITIONS
154            .read()
155            .map_err(|e| ObsError::LockError(format!("{:?}", e)))?;
156        let pos = pos
157            .get(&self.id)
158            .ok_or_else(|| ObsError::LockError("Position not found".to_string()))?;
159
160        Ok(*pos)
161    }
162
163    fn get_size(&self) -> Result<(u32, u32), ObsError> {
164        #[cfg(windows)]
165        if let Some(m) = self.child_window_handler.as_ref() {
166            let m = m
167                .read()
168                .map_err(|e| ObsError::LockError(format!("{:?}", e)))?;
169
170            return Ok((m.width, m.height));
171        }
172
173        let pointer = self.display.clone();
174        let (width, height) = run_with_obs!(self.runtime, (pointer), move || unsafe {
175            let mut w: u32 = 0;
176            let mut h: u32 = 0;
177
178            libobs::obs_display_size(pointer, &mut w, &mut h);
179            (w, h)
180        })
181        .map_err(|e| ObsError::InvocationError(format!("{:?}", e)))?;
182
183        Ok((width, height))
184    }
185}